package com.ls.cameraxtest;

import android.graphics.Point;
import android.os.Bundle;
import android.util.Size;
import android.view.LayoutInflater;
import android.view.OrientationEventListener;
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

import com.google.common.util.concurrent.ListenableFuture;

import java.io.File;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

import androidx.annotation.NonNull;
import androidx.camera.core.AspectRatio;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraControl;
import androidx.camera.core.CameraInfo;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.CameraX;
import androidx.camera.core.FocusMeteringAction;
import androidx.camera.core.FocusMeteringResult;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.ImageCaptureException;
import androidx.camera.core.MeteringPoint;
import androidx.camera.core.MeteringPointFactory;
import androidx.camera.core.Preview;
import androidx.camera.core.ZoomState;
import androidx.camera.core.impl.ImageCaptureConfig;
import androidx.camera.core.impl.PreviewConfig;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LiveData;
import androidx.navigation.fragment.NavHostFragment;

public class Camera2Fragment extends Fragment implements LifecycleOwner {

    private ImageCapture imageCapture;
    /** 带手势操作的PreviewView，如果不需要手势操作，可以直接使用PreviewView */
    private CameraXCustomPreviewView viewFinder;
    /** camera的相关信息，例如缩放级别等 */
    private CameraInfo mCameraInfo;
    /** 摄像头控制，例如缩放，对焦等 */
    private CameraControl mCameraControl;
    /** 摄像头选择实例，可以指定前或者后置摄像头 */
    private CameraSelector cameraSelector;
    private Button mBtnLight;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_camera2, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        ((MainActivity) getActivity()).setTitle("我们来用CameraX拍照");
        mBtnLight = view.findViewById(R.id.camera_flash_button);
        viewFinder = view.findViewById(R.id.viewFinder);
        view.findViewById(R.id.camera_capture_button).setOnClickListener(view1 -> {
            takePhoto();
        });
        mBtnLight.setOnClickListener(v->switchFlashMode());
        startCamera();
    }

    /**
     * 启动摄像头
     */
    private void startCamera() {
        //通过摄像头提供者获取摄像头代理对象
        ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(getContext());
        //注册一个相机准备完成的回调，参数为一个Runnable和Executor，此方式用于解耦操作，类似于相机准备好了，回调这边的主线程进行相关的
        //相机配置和初始化逻辑。
        cameraProviderFuture.addListener(() -> {
            // 相机准备完成，同步获取相机提供者对象
            ProcessCameraProvider cameraProvider = null;
            try {
                cameraProvider = cameraProviderFuture.get();
            } catch (ExecutionException | InterruptedException e) {
                e.printStackTrace();
                NavHostFragment.findNavController(this).popBackStack();
                return;
            }

            // 拍照配置
            imageCapture = new ImageCapture.Builder()
                    .setFlashMode(ImageCapture.FLASH_MODE_AUTO)//闪光模式
                    .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)//拍照模式，此模式拍照快但质量会差一点
                    .build();

            // 设置旋转监听
            setOrientationListener();

            // 预览配置
            Preview preview = new Preview.Builder().build();

            // 选择摄像头配置，现在选择的是后置摄像头
            cameraSelector = new CameraSelector.Builder()
                    .requireLensFacing(CameraSelector.LENS_FACING_BACK).build();

            // 图片分析配置，此处可以配置相关图片分析逻辑-例如二维码，人脸识别等
            ImageAnalysis imageAnalyzer = new ImageAnalysis.Builder()
                    //设置宽高比【setTargetAspectRatio与setTargetResolution只能同时设置一个】
                    .setTargetAspectRatio(AspectRatio.RATIO_16_9)
                    //设置实际尺寸
//                    .setTargetResolution(new Size(1920, 1080))
                    // 仅将最新图像传送到分析仪，并在到达图像时将其丢弃。
                    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                    .build();
            //选配 图像分析开启之后如果直接处理会导致画面卡顿-建议拿到图像数据之后用子线程进行分析处理
//            imageAnalyzer.setAnalyzer(ContextCompat.getMainExecutor(getContext()), image -> {
//                int rotationDegrees = image.getImageInfo().getRotationDegrees();
//                ImageProxy.PlaneProxy[] planes = image.getPlanes();
//                ByteBuffer buffer = planes[0].getBuffer();
//                // 转为byte[]
//                 byte[] b = new byte[buffer.remaining()];
//                // 此处进行数据分析。。。。。。
//                // 分析完成后关闭图像参考，否则会阻塞其他图像的产生
//                 image.close();
//            } );

            try {
                // 解绑其他相关，防止出现异常
                cameraProvider.unbindAll();
                // 设置好配置，通过相机提供者绑定生命周期会拿到camera对象
                Camera camera = cameraProvider.bindToLifecycle(Camera2Fragment.this,
                        cameraSelector, preview, imageCapture, imageAnalyzer);
                //配置预览界面
                mCameraInfo = camera.getCameraInfo();
                mCameraControl = camera.getCameraControl();
                preview.setSurfaceProvider(viewFinder.createSurfaceProvider(mCameraInfo));
                //选配，配置手势缩放对焦操作
                initCameraListener();
            } catch (Exception exc) {
                exc.printStackTrace();
                NavHostFragment.findNavController(this).popBackStack();
            }
        }, ContextCompat.getMainExecutor(getContext()));
    }

    /**
     * 配置摄像头缩放操作
     */
    private void initCameraListener() {
        if (mCameraInfo == null) {
            return;
        }
        LiveData<ZoomState> zoomState = mCameraInfo.getZoomState();
        float maxZoomRatio = zoomState.getValue().getMaxZoomRatio();
        float minZoomRatio = zoomState.getValue().getMinZoomRatio();
        //缩放过渡
        float spanRatio = 0.05f;
        viewFinder.setmCustomTouchListener(new CameraXCustomPreviewView.CustomTouchListener() {
            @Override
            public void zoom() {
                float zoomRatio = zoomState.getValue().getZoomRatio();
                if (zoomRatio + spanRatio < maxZoomRatio) {
                    mCameraControl.setZoomRatio((float) (zoomRatio + spanRatio));
                }
            }

            @Override
            public void ZoomOut() {
                float zoomRatio = zoomState.getValue().getZoomRatio();
                if (zoomRatio - spanRatio > minZoomRatio) {
                    mCameraControl.setZoomRatio((float) (zoomRatio - spanRatio));
                }
            }

            @Override
            public void click(float x, float y) {
                // 1.0.0-beta08 createMeteringPointFactory()方法已删除，Demo改为使用getMeteringPointFactory()
                MeteringPointFactory factory = viewFinder.createMeteringPointFactory(cameraSelector);
                MeteringPoint point = factory.createPoint(x, y);
                FocusMeteringAction action = new FocusMeteringAction.Builder(point, FocusMeteringAction.FLAG_AF)
                        // auto calling cancelFocusAndMetering in 3 seconds
                        .setAutoCancelDuration(3, TimeUnit.SECONDS)
                        .build();

                ListenableFuture<FocusMeteringResult> future = mCameraControl.startFocusAndMetering(action);
                future.addListener(() -> {
                    try {
                        FocusMeteringResult result = (FocusMeteringResult) future.get();
                        if (result.isFocusSuccessful()) {
                            //对焦成功
                        } else {
                            //对焦失败
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }, ContextCompat.getMainExecutor(getContext()));
            }

            @Override
            public void doubleClick(float x, float y) {
                // 双击放大缩小
                float zoomRatio = zoomState.getValue().getZoomRatio();
                if (zoomRatio > minZoomRatio) {
                    mCameraControl.setLinearZoom(0f);
                } else {
                    mCameraControl.setLinearZoom(0.5f);
                }
            }

            @Override
            public void longClick(float x, float y) {

            }
        });
    }


    /**
     * 设置屏幕旋转监听
     */
    private void setOrientationListener() {
        // 旋转监听-主要拥有设置拍摄图片的保存的旋转方向
        OrientationEventListener orientationEventListener = new OrientationEventListener(getContext()) {
            @Override
            public void onOrientationChanged(int orientation) {
                int rotation;
                // Monitors orientation values to determine the target rotation value
                if (orientation >= 45 && orientation < 135) {
                    rotation = Surface.ROTATION_270;
                } else if (orientation >= 135 && orientation < 225) {
                    rotation = Surface.ROTATION_180;
                } else if (orientation >= 225 && orientation < 315) {
                    rotation = Surface.ROTATION_90;
                } else {
                    rotation = Surface.ROTATION_0;
                }
                imageCapture.setTargetRotation(rotation);
            }
        };
        orientationEventListener.enable();
    }

    /**
     * 切换闪光灯模式
     */
    public void switchFlashMode() {
        switch (imageCapture.getFlashMode()) {
            case ImageCapture.FLASH_MODE_AUTO:
                imageCapture.setFlashMode(ImageCapture.FLASH_MODE_ON);
                mBtnLight.setText("闪光灯：开");
                break;
            case ImageCapture.FLASH_MODE_ON:
                imageCapture.setFlashMode(ImageCapture.FLASH_MODE_OFF);
                mBtnLight.setText("闪光灯：关");
                break;
            case ImageCapture.FLASH_MODE_OFF:
                imageCapture.setFlashMode(ImageCapture.FLASH_MODE_AUTO);
                mBtnLight.setText("闪光灯：自动");
                break;
            default:
        }
    }

    /**
     * 进行拍照
     */
    private void takePhoto() {
        // Get a stable reference of the modifiable image capture use case
        if (imageCapture == null) {
            return;
        }
        // 配置保存的文件夹
        File photoFile = new File(getContext().getExternalCacheDir(), System.currentTimeMillis() + "_cameraX.jpg");
        // 拍照保存文件的相关配置
        ImageCapture.OutputFileOptions outputOptions = new ImageCapture.OutputFileOptions.Builder(photoFile).build();
        // 进行拍照以及监听拍照完成的回调和异常回调
        imageCapture.takePicture(outputOptions, ContextCompat.getMainExecutor(getContext()), new ImageCapture.OnImageSavedCallback() {

            @Override
            public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
//                Uri savedUri = Uri.fromFile(photoFile);
//                String msg = "Photo capture succeeded: "+savedUri;
                ((MainActivity)getActivity()).saveImgToPics(getActivity(), photoFile.getAbsolutePath());
            }

            @Override
            public void onError(@NonNull ImageCaptureException exception) {
                exception.printStackTrace();
            }
        });
    }

}